/*
  CPU:  ESP32-S3

*/
#include <SPIFFS.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>

#include "common.h"
#include "config.h"

#include "BleManager.h"
#include "USBManager.h"

#include "HIDPS2conv_kb.h"
#include "HIDPS2conv_ms.h"
#include "ps2_client_kb.h"
#include "ps2_client_ms.h"

#include "webpage.h"
#include <ESPmDNS.h>
#include <WebServer.h>
#include <WiFi.h>

unsigned long t_key_fun = 0;
unsigned long t_wifi = 0;
bool open_wifi_setting = false;
const char *confFile = "/config.ini";
const char *confFileBak = "/config.ini.bak";
// 配置热点的名称和密码
char ssid[33] = {0};            // 热点名称
char password[17] = "12345678"; // 热点密码（至少8个字符）
// 自定义AP的IP配置
IPAddress local_IP(192, 168, 1, 1); // ESP32自身的IP地址
IPAddress gateway(192, 168, 1, 1);  // 网关地址（通常与IP相同）
IPAddress subnet(255, 255, 255, 0); // 子网掩码

// Web服务
WebServer server(80);

PS2_Client_MS _PS2_Client_MS;
PS2_Client_KB _PS2_Client_KB;

void USB_OnConnect(uint8_t usbNum, bool &bFlag);
void USB_OnDisconnect(uint8_t usbNum);
void BLE_pair(String address);
void initAdapter(char *ssid);

void saveConfig() {
    SPIFFS.remove(confFileBak);
    SPIFFS.rename(confFile, confFileBak);

    File file1 = SPIFFS.open(confFileBak, FILE_READ);
    File file2 = SPIFFS.open(confFile, FILE_WRITE);

    char line[256]; // 假设每行不超过256个字符
    // 跳过[SYSTEM] (直到读到[WIFI])
    while (file1.available()) {
        // 读取一行数据（直到遇到换行符'\n'）
        int len = file1.readBytesUntil('\n', line, sizeof(line) - 1);
        line[len - 1] = '\0'; // 添加字符串结束符
        file2.println(line);
        if (strcmp("[WIFI]", line) == 0) {
            break;
        }
    }
    file1.close();

    // 用户wifi名字
    file2.println("-ssid:");
    file2.println(ssid);
    // 用户wifi密码
    file2.println("-password:");
    file2.println(password);

    file2.println("[BLE]");
    for (int i = 0; i < HID_COUNT; i++) {
        HIDPS2conv_HIDPoint &hidPt = HIDPS2conv::s_hidPoint[i];
        if (hidPt.type == 1) {

            file2.println("-address:");
            file2.println(hidPt.pBleServerConnector->_address);
            file2.println("-addressType:");
            file2.println(hidPt.pBleServerConnector->_addressType);
            file2.println("-name:");
            file2.println(hidPt.pBleServerConnector->_name);
            file2.println("-deviceType:");
            file2.println(hidPt.pBleServerConnector->_type);
            file2.println("-keyboard_mode:");
            file2.println(hidPt.pBleServerConnector->_keyboard_mode);
        }
    }

    file2.close();
}

// 从EEPROM读取配置信息
void readConfig() {
    File file = SPIFFS.open(confFile, FILE_READ);
    if (!file) {
        return;
    }

    char line[256]; // 假设每行不超过256个字符

    // SYSTEM]
    while (file.available()) {
        int len = file.readBytesUntil('\n', line, sizeof(line) - 1);
        line[len - 1] = '\0'; // 滤掉 '\r'
        if (strcmp("[WIFI]", line) == 0) {
            break;
        }
    }

    // [WIFI]
    while (file.available()) {
        int len = file.readBytesUntil('\n', line, sizeof(line) - 1);
        line[len - 1] = '\0';

        if (strcmp("[BLE]", line) == 0) {
            break;
        } else if (strcmp("-ssid:", line) == 0) {
            len = file.readBytesUntil('\n', line, sizeof(line) - 1);
            line[len - 1] = '\0';
            strcpy(ssid, line);
        } else if (strcmp("-password:", line) == 0) {
            len = file.readBytesUntil('\n', line, sizeof(line) - 1);
            line[len - 1] = '\0';
            strcpy(password, line);
        }
    }

    // [BLE]
    char name[33] = {0};
    char address[18] = {0};
    uint8_t addressType = 0;
    int deviceType = 0;
    int keyboard_mode = 0;

    while (file.available()) {
        int len = file.readBytesUntil('\n', line, sizeof(line) - 1);
        line[len - 1] = '\0';
        if (strcmp("-address:", line) == 0) {
            len = file.readBytesUntil('\n', line, sizeof(line) - 1);
            line[len - 1] = '\0';
            strcpy(address, line);
        } else if (strcmp("-addressType:", line) == 0) {
            len = file.readBytesUntil('\n', line, sizeof(line) - 1);
            line[len - 1] = '\0';
            addressType = atoi(line);
        } else if (strcmp("-name:", line) == 0) {
            len = file.readBytesUntil('\n', line, sizeof(line) - 1);
            line[len - 1] = '\0';
            strcpy(name, line);
        } else if (strcmp("-deviceType:", line) == 0) {
            len = file.readBytesUntil('\n', line, sizeof(line) - 1);
            line[len - 1] = '\0';
            deviceType = atoi(line);
        } else if (strcmp("-keyboard_mode:", line) == 0) {
            len = file.readBytesUntil('\n', line, sizeof(line) - 1);
            line[len - 1] = '\0';
            keyboard_mode = atoi(line);

            // 创建BLE连接
            _BleManager.createConnection(address, addressType, deviceType, name);
            // 开启配对
            BLE_pair(address);
        }
    }

    file.close();
}

void setup() {
    _PS2_Client_MS.init(ps2_ms_clk, ps2_ms_d);
    _PS2_Client_KB.init(ps2_kb_clk, ps2_kb_d);
    _HIDPS2conv_KB.init(&_PS2_Client_KB);
    _HIDPS2conv_MS.init(&_PS2_Client_MS);
    Serial.begin(115200);

    !SPIFFS.begin(true);

    pinMode(KEY_FUN, INPUT_PULLUP);
    pinMode(led_B_, OUTPUT);
    pinMode(led_R_, OUTPUT);
    digitalWrite(led_B_, HIGH); // 关灯
    digitalWrite(led_R_, HIGH); // 关灯

    delay(10);

    // 开启蓝牙
    NimBLEDevice::setPower(-12);
    _BleManager.init("PS/2_adapter");

    // Wifi及Web服务
    // 配置自定义IP地址
    WiFi.setTxPower(WIFI_POWER_MINUS_1dBm);
    WiFi.softAPConfig(local_IP, gateway, subnet);
    WiFi.mode(WIFI_OFF);
    // Web服务
    server.on("/", handleRoot);
    server.on("/devices", handleDevices);
    server.on("/common.css", handleCSS);
    server.on("/common.js", handleJS);

    server.onNotFound(handleNotFound);

    t_key_fun = millis();
    t_wifi = 0;

    // 配置USB
    // 设置引脚，设备描述符回调，报表回调
    _USBManager.init(USB_DP0, USB_DM0,
                     USB_DP1, USB_DM1,
                     -1, -1,
                     -1, -1);
    _USBManager.setOnConnect(USB_OnConnect);
    _USBManager.setOnDisonnect(USB_OnDisconnect);

    _SUSB.BusSuspend();
    readConfig();
    _SUSB.BusResume();
}

void loop() {
    static unsigned long tFlash = millis();
    static int blink = 0;

    // 长按key_fun3秒将开启WIFI,可进行设备的配置
    // 3分钟不连接wifi热点或进行设置将关闭wift及web服务
    if (!digitalRead(KEY_FUN)) {
        // 按下
        if (millis() - t_key_fun > 1500) {
            // 超过1.5秒
            if (!open_wifi_setting) {
                // 启动AP模式
                Serial.println("启动AP模式");
                _SUSB.BusSuspend();
                if (ssid[0] == 0) {
                    initAdapter(ssid);
                }
                if (WiFi.softAP(ssid, password)) {
                    Serial.print("AP热点已创建，SSID: ");
                    Serial.println(ssid);

                    server.begin();
                    Serial.println("HTTP server started");

                    // 开始计时
                    open_wifi_setting = true;
                    digitalWrite(led_R_, HIGH); // 关红灯--闪蓝灯
                    t_wifi = millis();
                }
            }
        }

    } else {
        t_key_fun = millis();
    }

    if (open_wifi_setting) {
        server.handleClient();

        // 短按key_fun,或者三分钟后关闭wifi
        if (millis() - t_wifi > 180000 || (millis() - t_key_fun < 1000 && !digitalRead(KEY_FUN))) {

            Serial.println("关闭设置模式");
            server.stop();   // 关闭服务器
            vTaskDelay(100); // 短暂延时确保资源释放

            // 关闭热点
            Serial.println("关闭热点");
            WiFi.softAPdisconnect(true);
            WiFi.mode(WIFI_OFF);
            // 保存设置
            saveConfig();
            Serial.println("关灯");
            digitalWrite(led_B_, HIGH);

            _SUSB.BusResume();
            open_wifi_setting = false;
        }

        if (timePassed(tFlash, 500)) {
            // 闪蓝灯
            blink = 1 - blink;
            digitalWrite(led_B_, blink);
        }
    } else {
        // 根据连接状态亮（闪）灯
        // 红闪：无任何设备
        // 红亮：只有USB设备
        // 蓝亮：只有蓝牙设备
        // 都亮：有USB和蓝牙设备
        // 蓝闪：WIFI打开，设置模式
        if (timePassed(tFlash, 500)) {
            blink = 1 - blink;
            digitalWrite(led_R_, blink);
        }
    }

    _SUSB.checkEvent();
    _PS2_Client_KB.makeData();
    _PS2_Client_MS.makeData();
    _PS2_Client_KB.sendBuffer();
    _PS2_Client_KB.readAndExec();
    _PS2_Client_MS.sendBuffer();
    _PS2_Client_MS.readAndExec();

    vTaskDelay(1);
}

void BLE_remove(String address) {
    BleServerConnector *connector = BleManager::getBleServerConnector(address);
    if (!connector) {
        return;
    }

    _BleManager.removePairedDevice(connector);
    HIDPS2conv::removeHidDevice(connector);
}

void BLE_pair(String address) {
    BleServerConnector *connector = BleManager::getBleServerConnector(address);
    if (!connector) {
        return;
    }

    if (connector->_type == 1) {
        if (_HIDPS2conv_KB.addHidDevice(connector)) {
            _BleManager.pairDevice(connector);
        }
    } else if (connector->_type == 2) {
        if (_HIDPS2conv_MS.addHidDevice(connector)) {
            _BleManager.pairDevice(connector);
        }
    }
}

void BLE_scan() {
    _BleManager.startScan();
}

void USB_OnConnect(uint8_t usbNum, bool &bFlag) {
    bFlag = false;
    USBClientConnector *connector = USBManager::getUSBClientConnector(usbNum);
    if (!connector) {
        return;
    }

    if (connector->_type == 1) {
        bFlag = _HIDPS2conv_KB.addHidDevice(connector);
    } else if (connector->_type == 2) {
        bFlag = _HIDPS2conv_MS.addHidDevice(connector);
    }
}

void USB_OnDisconnect(uint8_t usbNum) {
    USBClientConnector *connector = USBManager::getUSBClientConnector(usbNum);
    if (connector) {
        HIDPS2conv::removeHidDevice(connector);
    }
}

void initAdapter(char *ssid) {
    // 初始ssid
    randomSeed(micros());
    sprintf(ssid, "PS/2_adapter_%02x%02x%02x%02x", random(256), random(256), random(256), random(256));

    File file = SPIFFS.open(confFile, FILE_WRITE);

    file.println("[SYSTEM]");
    // 写入设备名
    file.println("-deviceName:");
    file.println("PS/2 Adapter");
    // 初始wifi名字
    file.println("-ssid:");
    file.println(ssid);
    // 初始wifi密码
    file.println("-password:");
    file.println(password);

    file.println("[WIFI]");
    // 用户wifi名字
    file.println("-ssid:");
    file.println(ssid);
    // 用户wifi密码
    file.println("-password:");
    file.println(password);

    file.println("[BLE]");

    file.close();
}